Repository navigation
Conversation
…dget A provider can report an exhausted budget without asking for a long wait and without any recognisable phrase in the message. `retryable` only looks at prose, so those responses run the full five attempts and the session waits for a limit that resets on a billing or daily window. Classify the documented structural signals instead: HTTP 402, the OpenAI billing error codes, and a google QuotaFailure whose quota id names a per-day window. Those end the schedule after the retry status is published, so the UI still reports the limit and the error then reaches the caller. Per-minute quotas, plain 429s and everything else keep their current retry behavior.
|
The following comment was made by an LLM, it may be inaccurate: Related PRs Found:
Context: The PR description explicitly states these three PRs are complementary and compose together:
These are not duplicates — they address different aspects of the retry classification problem and all three are meant to work together. The PR description confirms none subsumes another. |
|
Automated PR Cleanup Thank you for contributing to opencode. Due to the high volume of PRs from users and AI agents, we periodically close older PRs using automated criteria so maintainers can focus review time on the most active and community-supported contributions. This PR was closed because it matched the following cleanup criteria:
PRs created within the last month are not affected by this cleanup. If you believe this PR was closed incorrectly, or if you are still actively working on it, please leave a comment explaining why it should be reopened. A maintainer can review and reopen it if appropriate. Thanks again for taking the time to contribute. |
Issue for this PR
Closes #47685
Type of change
What does this PR do?
retryable()decides whether a provider error is worth another attempt by looking at prose — themessage and the response body run through
RETRYABLE_MESSAGE_PATTERNS, plus two zen-specificmarkers. A provider that reports an exhausted budget without a recognisable phrase, and without
asking for a long
retry-after, falls through as an ordinary retryable error. The session thenspends all five attempts on a limit that resets on a billing or daily window.
This classifies the documented structural signals instead of the wording:
insufficient_quota,billing_hard_limit_reached,billing_not_active,account_deactivated), read fromerror.type/error.codeor thetop-level
code/type,QuotaFailurewhosequotaId/quotaMetricnames a per-day window.These are stable identifiers rather than message text, which varies per provider and locale.
A terminal result ends the schedule, but only after the retry status has been published, so the UI
reports the limit exactly as it does today and the error then reaches the caller instead of a
pending attempt. Per-minute quotas, plain 429s, 5xx and everything else keep their current retry
behavior — the new checks run after the existing classification and only add a
terminalflag.Relation to the other open PRs in this area, since they overlap in this file: #47339 stops on
the
free_tier_limitandaccount_rate_limitreasons, which are derived from zen markers in thebody; #47641 stops when the requested wait exceeds a ceiling. This PR covers the case neither
reaches — a structural budget signal with a short or absent
retry-afterand no zen marker. Allthree compose; none of them subsumes another.
How did you verify your code works?
Five new tests in
packages/opencode/test/session/retry.test.ts, additive — no existingexpectation was changed:
insufficient_quotabody is terminal,QuotaFailureis terminal,QuotaFailurestays retryable,Verified the three terminal cases fail on unmodified
devand pass with the change.bun test test/session/retry.test.tsinpackages/opencode: 65 pass, 0 failtsgo --noEmitinpackages/opencode: cleanprettier --checkon both changed files: cleanoxlinton the changed file: 2 warnings, the same two present ondevbefore this changeNot verified: an exhausted account against a live provider. The classification is driven by the
documented response shapes, and the tests use those shapes verbatim.
Screenshots / recordings
Not a UI change.
Checklist